#ifndef COMMON_HPP
#define COMMON_HPP
#include <QtCore>
#include <QtDBus>
#include <qdom.h>
#define DBUS_TYPE_STRUCT QMetaType::User+2001
#define DBUS_TYPE_DICT   QMetaType::User+2002
#define DBUS_TYPE_ARRAR  QMetaType::User+2003
#define LEVEL_ROOT 0
#define LEVEL_TOP 1

#define METHOD_NAME "Method"
#define METHOD_LIST "Methods"
#define METHOD_BUS_NAME "BUS"
#define METHOD_BUS_SERVICE "SERVICE"
#define METHOD_BUS_PATH "PATH"
#define METHOD_BUS_INTERFACE "INTERFACE"
#define METHOD_TYPE "TYPE"
#define METHOD_ARG_TYPE "ARGS_TYPE"
#define METHOD_ARG_NAME "NAME"
#define METHOD_ARGS "ARGS"
#define METHOD_ARG_VALUE "VALUE"





#define DBUS_NAME_SESSION "Session"
#define DBUS_NAME_SYSTEM "System"

#define Setting_DeviceDlg_main "DeviceDlg_main"
#define Setting_DeviceDlg_Value "DeviceDlg_Value"
#define Setting_DeviceDlg_Host_Type "DeviceDlg_Host_Type"
#define Setting_DeviceDlg_Host_IP "DeviceDlg_Host_IP"
#define Setting_DeviceDlg_Host_Port "DeviceDlg_Host_Port"
#define Setting_DeviceDlg_Host_Service "DeviceDlg_Host_Service"
#define Setting_DeviceDlg_Host_Path "DeviceDlg_Host_Path"
#define Setting_DeviceDlg_Host_Interface "DeviceDlg_Host_Path"


#define Setting_MainWindow_main "MainWindow_main"
#define Setting_MainWindow_DbusObjectView_Value "MainWindow_DbusObjectView_Value"
#define Setting_MainWindow_DbusObjectView_table_list "MainWindow_DbusObjectView_table_list"
#define Setting_MainWindow_DbusObjectView_table_currentIndex "MainWindow_DbusObjectView_table_currentIndex"
#define Setting_MainWindow_DbusObjectView_table_ColumnHidden "DbusObjectView_table_ColumnHidden"
#define Setting_MainWindow_DbusObjectView_table_list "MainWindow_MethodView_table_list"


#define METHOD "Method"
#define METHOD_NAME "Name"
#define METHOD_SKIP "SKIP"
#define METHOD_BUS_NAME "BUS"
#define METHOD_BUS_CATEGORY "CATEGORY"
#define METHOD_BUS_SERVICE "SERVICE"
#define METHOD_BUS_PATH "PATH"
#define METHOD_BUS_INTERFACE "INTERFACE"
#define METHOD_TYPE "ArgTypeId"
#define METHOD_CAPTION "CAPTION"
#define METHOD_SIGNATUR "SIGNATUR"

#define METHOD_ARGS "ARGS"
#define METHOD_ARG "ARG"

#define ARG_VALUES "ARG_VALUES"
#define ARG_VALUE "ARG_VALUE"

#define METHOD_ARG_SHOW_MODEL "Show_Model"
#define METHOD_ARG_TYPE "TYPE"
#define METHOD_ARG_NAME "NAME"
#define METHOD_ARG_VALUE "VALUE"
#define METHOD_ARG_DICT_KEY "KEY"
#define METHOD_ARG_DICT "DICT"
#define METHOD_ARG_SUB_TYPE "SUBTYPE"



struct DVariant;
struct dict;
struct array;
struct structs;

void DbusArg2Xml(QDomDocument docx,QDomElement &value,const DVariant &v);
void DbusArg2Xml(QDomDocument docx,QDomElement &value,const QVariant &v);
void DbusArg2Xml(QDomDocument docx,QDomElement &value,const QDBusArgument &v);

bool Xml2DbusArg(QDomDocument docx,QDomElement &value, DVariant &v);
bool Xml2DbusArg(QDomDocument docx,QDomElement &value, QVariant &v);
bool Xml2DbusArg(QDomDocument docx,QDomElement &value, QDBusArgument &v);

enum ItemType { InterfaceItem, PathItem, MethodItem, SignalItem, PropertyItemReadwrite, PropertyItemRead, PropertyItemWrite,LocalMethod };

enum EndSymbol {
    EndSymbolNone,
    EndSymbol0A,
    EndSymbol0D,
    EndSymbol0A0D,
    EndSymbol0D0A
};

enum ShowModel {
    ShowModelDefault,
    ShowModelDec,
    ShowModelHex
};

struct dict
{
    QList<DVariant> keys;
    QList<DVariant> Values;
    bool operator==(const dict s) const;
    QList<int> m_Subtypes;
    QString m_argTypes;
};
Q_DECLARE_METATYPE(dict)
struct array
{
  QList<DVariant> Values;
  bool operator==(const array s) const;
  QList<int> m_Subtypes;
  QString m_argTypes;
};
Q_DECLARE_METATYPE(array)
struct structs
{
public:
    QList<DVariant> Values;
    bool operator==(const structs s) const;
    QList<int> m_Subtypes;
    QString m_argTypes;
} ;
Q_DECLARE_METATYPE(structs)

enum Flag {
    Flag_ERROR_EMPTY = -1,
    Flag_ERROR_DICT_KEY = -2,
    Flag_ERROR_DICT_VALUE = -3,
    Flag_ERROR_ARRAY_VALUE = -4,
    Flag_ERROR_STRUCT = -5,
    Flag_BASE_SUCCESS = 1,
    Flag_ARRAY_SUCCESS = 2,
    Flag_DICT_SUCCESS = 3,
    Flag_STRUCT_SUCCESS = 4,
};
struct DVariant
{
    DVariant();
    QString toPlainText();
    QString toXmlText();
    bool toXml(QDomDocument &docx,QDomElement &value);
    bool fromXml(QDomDocument &docx,QDomElement &value);


    bool toQDBusArgument(QDBusArgument &dbus_arg);
    bool operator==(const DVariant s) const;
    void setValue(QVariant d);

    void setValue(QVariant d,int type){
        m_Values = d;
        m_type = type;
    }
    void setValue(dict d);
    void setValue(array d);
    void setValue(structs d);
    void setValue(QDBusObjectPath d);
    void setValue(QDBusSignature d);
    void setValue(QDBusUnixFileDescriptor d);
    void setValue(uint8_t d);
    void setValue(uint16_t d);
    void setValue(int16_t d);
    void setValue(uint32_t d);
    void setValue(int32_t d);
    void setValue(uint64_t d);
    void setValue(int64_t d);
    void setValue(QByteArray d);
    void setValue(QDBusVariant d);

    QVariant getVariant(bool *ok = Q_NULLPTR) const;

    dict getDict(bool *ok = Q_NULLPTR) const;
    array getArray(bool *ok = Q_NULLPTR) const;
    structs getStruct(bool *ok = Q_NULLPTR) const;
    uint8_t getUInt8(bool *ok = Q_NULLPTR) const;
    bool getBool(bool *ok = Q_NULLPTR) const
    {
        if(ok != Q_NULLPTR)
            *ok = true;
        return m_Values.toBool();
    }
    uint16_t getUInt16(bool *ok = Q_NULLPTR) const;
    int16_t getInt16(bool *ok = Q_NULLPTR) const;
    uint32_t getUInt32(bool *ok = Q_NULLPTR) const;
    int32_t getInt32(bool *ok = Q_NULLPTR) const;
    int64_t getInt64(bool *ok = Q_NULLPTR) const;
    uint64_t getUInt64(bool *ok = Q_NULLPTR) const;
    QString getString(bool *ok = Q_NULLPTR) const;
    QByteArray getByteArray(bool *ok = Q_NULLPTR)  const;


    int type() const;
    QString getArgType() const;
    QList<int> getSubtypes() const;
    void setSubtypes(const QList<int> &Subtypes);
    QString getArgTypes() const;
    void setArgTypes(const QString &argTypes);

public:
    QVariant m_Values;
    int m_type;
    QList<int> m_Subtypes;
    QString m_argTypes;
    ShowModel m_showModel;

} ;
Q_DECLARE_METATYPE(DVariant)


struct BusSignatureEx
{
    QString mBus,mService, mPath, mInterface, mName;
    QString mTypeSig;
    int type;
    QStringList argNames;
    QStringList argTypes;
    void  toContext(QDomDocument docx,QDomElement &child)
    {
        child.setAttribute (METHOD_BUS_NAME,mBus);
        child.setAttribute (METHOD_BUS_SERVICE,mService);
        child.setAttribute (METHOD_BUS_PATH,mPath);
        child.setAttribute (METHOD_BUS_INTERFACE,mInterface);
        child.setAttribute (METHOD_NAME,mName);
        child.setAttribute (METHOD_BUS_CATEGORY,type);
        QDomElement child_args = docx.createElement (METHOD_ARGS);
        for(int i=0;i<argTypes.count ();i++)
        {
            QDomElement child_arg = docx.createElement (METHOD_ARG);
            child_arg.setAttribute (METHOD_TYPE,argTypes.at (i));
            if(argNames.count ()>i)
            {
                child_arg.setAttribute (METHOD_NAME,argNames.at (i));
            }
            child_args.appendChild (child_arg);
        }
        child.appendChild (child_args);
        docx.appendChild (child);
    }
    void  setContext(QDomDocument docx,QDomElement child)
    {
        if(child.isNull ())
        {
            return;
        }
        if(child.hasAttribute (METHOD_BUS_NAME))
        {
            mBus = child.attribute (METHOD_BUS_NAME);
        }
        if(child.hasAttribute (METHOD_BUS_SERVICE))
        {
            mService = child.attribute (METHOD_BUS_SERVICE);
        }
        if(child.hasAttribute (METHOD_BUS_PATH))
        {
            mPath = child.attribute (METHOD_BUS_PATH);
        }
        if(child.hasAttribute (METHOD_BUS_INTERFACE))
        {
            mInterface = child.attribute (METHOD_BUS_INTERFACE);
        }
        if(child.hasAttribute (METHOD_NAME))
        {
            mName = child.attribute (METHOD_NAME);
        }
        if(child.hasAttribute (METHOD_BUS_CATEGORY))
        {
            type = child.attribute (METHOD_BUS_CATEGORY).toInt ();
        }
        QDomElement child_args = child.firstChildElement(METHOD_ARGS);
        if(child_args.isNull ())
        {
            return;
        }
        QDomElement child_arg = child_args.firstChildElement(METHOD_ARG);
        while(!child_arg.isNull ())
        {
            if(child_arg.hasAttribute (METHOD_TYPE))
            {
                argTypes.append ( child_arg.attribute (METHOD_TYPE));
            }
            if(child_arg.hasAttribute (METHOD_NAME))
            {
                argNames.append ( child_arg.attribute (METHOD_NAME));
            }
            child_arg = child_arg.nextSiblingElement(METHOD_ARG);
        }
    }

};
Q_DECLARE_METATYPE(BusSignatureEx)

struct QDBusObject
{
    QDBusObject(QDBusObject *aParent = 0)
        : parent(aParent),m_data()
    {
    }
    QDBusObject(const BusSignatureEx data, QDBusObject *aParent = 0)
        : parent(aParent),m_data(data)
    {
    }
    QByteArray toContext()
    {
       QDomDocument docx;
       QDomElement methods = docx.createElement (METHOD_LIST);
       for(int i=0;i<children.count ();i++)
       {
           if(children.at (i)->m_data.type != LocalMethod)
           {
               QDomElement child = docx.createElement (METHOD);
               children.at (i)->m_data.toContext (docx,child);
               methods.appendChild (child);
           }
       }
       docx.appendChild (methods);
       return docx.toByteArray ();
    }
    void  setContext(QByteArray context)
    {
        QDomDocument docx;
        QString errorStr;
        int errorLine;
        int errorColumn;
        qDeleteAll(children);
        children.clear ();

        if(docx.setContent (context,true, &errorStr, &errorLine,&errorColumn))
        {
            QDomElement root = docx.documentElement();
            QDomElement child = root.firstChildElement (METHOD);
            while (!child.isNull ()) {
                BusSignatureEx data;
                data.setContext (docx,child);
                if(data.type!=LocalMethod)
                {
                    children.append (new QDBusObject(data,this));
                }
                child = child.nextSiblingElement (METHOD);
            }
        }
    }

    ~QDBusObject()
    {
        qDeleteAll(children);
    }
    QDBusObject *parent;
    QVector<QDBusObject *> children;
    BusSignatureEx m_data;
};
Q_DECLARE_METATYPE(QDBusObject)
struct DbusMethodItem
{
    DbusMethodItem(DbusMethodItem *aParent = 0)
        : parent(aParent),m_data()
    {
    }
    DbusMethodItem(const BusSignatureEx data, DbusMethodItem *aParent = 0)
        : parent(aParent),m_data(data)
    {
    }
    QByteArray toContext()
    {
       QDomDocument docx;
       for(int i=0;i<children.count ();i++)
       {
           QDomElement child = docx.createElement (METHOD);
           children.at (i)->m_data.toContext (docx,child);
           docx.appendChild (child);
       }
       return docx.toByteArray ();
    }
    void  setContext(QByteArray context)
    {
        QDomDocument docx;
        QString errorStr;
        int errorLine;
        int errorColumn;
        children.clear ();
        if(docx.setContent (context,true, &errorStr, &errorLine,&errorColumn))
        {
            QDomElement child = docx.firstChildElement (METHOD);
            while (!child.isNull ()) {
                BusSignatureEx data;
                data.setContext (docx,child);
                children.append (new DbusMethodItem(data,this));
                child = child.nextSiblingElement (METHOD);
            }
        }
    }

    ~DbusMethodItem()
    {
        qDeleteAll(children);
    }

    DbusMethodItem *parent;
    QVector<DbusMethodItem *> children;
    BusSignatureEx m_data;
};
Q_DECLARE_METATYPE(DbusMethodItem)
struct DbusTestModelItem
{
    DbusTestModelItem(DbusTestModelItem *aParent = 0)
        : parent(aParent),m_data()
    {
        m_starttime = 0;
        m_finshtime = 0;
        m_error = 0;
        m_errMsg = "";
        m_skip = false;
    }
    DbusTestModelItem(const BusSignatureEx data,QList<DVariant> Args, DbusTestModelItem *aParent = 0)
        : parent(aParent),m_data(data),dbusArgs(Args)
    {
        m_starttime = 0;
        m_finshtime = 0;
        m_error = 0;
        m_errMsg = "";
        m_skip = false;
    }

    ~DbusTestModelItem(){
        qDeleteAll(children);
    };

    QString toContext()
    {
       QDomDocument docx;
       QDomElement methods = docx.createElement (METHOD_LIST);
       foreach (DbusTestModelItem* var, children) {
           QDomElement child = docx.createElement (METHOD);
           var->m_data.toContext (docx,child);
           if(var->skip ())
           {
               child.setAttribute (METHOD_SKIP,"Skip");
           }
           QDomElement args = docx.createElement (ARG_VALUES);
           foreach (DVariant arg,var->dbusArgs) {
               QDomElement argx = docx.createElement (ARG_VALUE);
               arg.toXml (docx,argx);
               args.appendChild (argx);
           }
           child.appendChild (args);
           methods.appendChild (child);
       }
       docx.appendChild (methods);
       return docx.toString ();
    }
    void  setContext(QString context)
    {
        QDomDocument docx;
        QString errorStr;
        int errorLine;
        int errorColumn;
        qDeleteAll(children);
        children.clear ();
        if(docx.setContent (context,true, &errorStr, &errorLine,&errorColumn))
        {
            QDomElement root = docx.documentElement();
            QDomElement child = root.firstChildElement (METHOD);
            while (!child.isNull ()) {
                BusSignatureEx data;
                data.setContext (docx,child);

                QList<DVariant> Args;
                QDomElement xmlArgs = child.firstChildElement (ARG_VALUES);
                if(!xmlArgs.isNull ())
                {
                    QDomElement xmlArg = xmlArgs.firstChildElement (ARG_VALUE);
                    while (!xmlArg.isNull ()) {
                        DVariant d;
                        d.fromXml (docx,xmlArg);
                        Args.append (d);
                        xmlArg = xmlArg.nextSiblingElement(ARG_VALUE);
                    }
                }
                DbusTestModelItem *item = new DbusTestModelItem(data,Args, this);
                if(child.hasAttribute (METHOD_SKIP))
                {
                    item->setSkip (true);
                }else
                {
                    item->setSkip (false);
                }
                children.append (item);
                child = child.nextSiblingElement (METHOD);
            }
        }
    }
    DbusTestModelItem *parent;
    QVector<DbusTestModelItem *> children;
    BusSignatureEx m_data;
    QList<DVariant> dbusArgs;
    qlonglong m_starttime;
    qlonglong m_finshtime;
    int m_error;
    QString m_errMsg;
    bool m_skip;
private:
    QString m_result;

public:
    bool skip() const;
    void setSkip(bool skip);
    QString result() const;
    void setResult(const QString &result);
};
Q_DECLARE_METATYPE(DbusTestModelItem)
#endif // COMMON_HPP
